package mongodb.general.operator.nodb.utils;

import lombok.extern.slf4j.Slf4j;
import mongodb.general.operator.nodb.vo.MongoRequestParamsHandler;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Order;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Pattern;

/**
 * mongodb查询处理
 */
@Slf4j
public class CommonMongoHandleUtils {
    /**
     * 根据请求参数得到Query对象
     *
     * @param
     * @return
     * @throws ParseException
     */
    public static Query getQuery(MongoRequestParamsHandler paramsHandler) throws Exception {
        // 获得构造Query对象的map
        Map<String, Object> paramsMap = paramsHandler.getParamsMap();
        Query query = new Query();
//        wrapQuery(query, paramsMap, paramsHandler);
        //不向外暴露除getQuery以外的方法
        CommonMongoHandleUtils utils = new CommonMongoHandleUtils();
        utils.wrapQuery(query, paramsMap, paramsHandler);
        return query;
    }

    private void wrapQuery(Query query, Map<String, Object> paramsMap, MongoRequestParamsHandler paramsHandler) throws Exception {
        wrapQueryRecursively(query, paramsMap, paramsHandler);
        wrapOrOperationQuery(query,paramsHandler);
        wrapQueryResponse(query, paramsHandler.getResponseParameters());
        //包装非空查询
        if (paramsHandler.isNotNull()) {
            wrapNotNullOperationQuery(query, paramsHandler.getNotNullList());
        }
        //包装空值查询
        if (paramsHandler.isNull()) {
            wrapNullOperationQuery(query, paramsHandler.getNullList());
        }
        wrapSortBy(query, paramsHandler.getSortBy());
    }

    /**
     * 递归地构造Query对象
     */
    private void wrapQueryRecursively(Query query, Map<String, Object> paramsMap, MongoRequestParamsHandler paramsHandler) throws Exception {
        for (String key : paramsMap.keySet()) {
            // 范围查询
            if (paramsHandler.isRange(key)) {
                if (paramsMap.get(key) instanceof List) {
                    List<String> rangePair = (List) paramsMap.get(key);
                    //获取区间比较类型
                    String ruleType = paramsHandler.getType(key);
                    if (rangePair.get(0) instanceof String) {
                        wrapDateAreaQuery(query, key, rangePair.get(0), rangePair.get(1), ruleType);
                        //数字范围查询
                    } else {
                        wrapNumAreaQuery(query, key, rangePair.get(0), rangePair.get(1), ruleType);
                    }

                }
                //in查询
            } else if (paramsHandler.isInOperation(key)) {
                wrapInOperationQuery(query, key, paramsMap.get(key));
                //模糊查询，待优化功能
            } else if (paramsHandler.isFuzz(key)) {
                wrapLikeQuery(query, key, (String) paramsMap.get(key));
                // 子列表嵌套查询
            } else if (paramsHandler.isSubListField(key)) {
                List<Map<String, Object>> subList = (List<Map<String, Object>>) paramsMap.get(key);
                Map<String, Object> subMap = subList.get(0);
//                Map<String, Object> subMapWithKeyPrefix = new HashMap<>();
                Criteria cri = new Criteria();
                Field criteriaChain = cri.getClass().getDeclaredField("criteriaChain");
                criteriaChain.setAccessible(true);
                List<Criteria> criteriaList = (List<Criteria>)criteriaChain.get(cri);
                subMap.forEach((k, v) -> {
                    criteriaList.add(Criteria.where(k).is(v));
                });
                query.addCriteria(Criteria.where(key).elemMatch(cri));
//                wrapQueryRecursively(query, subMapWithKeyPrefix, paramsHandler, key);
            } else {
                wrapNormalQuery(query, key, paramsMap.get(key));
            }
        }
    }
    /**
     * 包装日期区间查询query条件
     */
    private void wrapDateAreaQuery(Query query, String key, String start, String end, String ruleType) throws Exception {
        SimpleDateFormat dateFormat = new SimpleDateFormat(DateUtils.simpleDate);
        //为日期的场合
        if (DateUtils.datePattern.matcher(start).find() && DateUtils.datePattern.matcher(end).find()) {
            Date startDate = dateFormat.parse(start);
            Date endDate = dateFormat.parse(end);
            if (">".equals(ruleType)) {
                query.addCriteria(Criteria.where(key).gt(startDate));
            } else if (">=".equals(ruleType)) {
                query.addCriteria(Criteria.where(key).gte(startDate));
            } else if ("<".equals(ruleType)) {
                query.addCriteria(Criteria.where(key).lt(endDate));
            } else if ("<=".equals(ruleType)) {
                query.addCriteria(Criteria.where(key).lte(endDate));
            } else if ("><=".equals(ruleType)) {
                query.addCriteria(Criteria.where(key).gt(startDate).lte(endDate));
            } else if (">=<".equals(ruleType)) {
                query.addCriteria(Criteria.where(key).gte(startDate).lt(endDate));
            } else if ("><".equals(ruleType)) {
                query.addCriteria(Criteria.where(key).gt(startDate).lt(endDate));
            }  else {
                query.addCriteria(Criteria.where(key).gte(startDate).lte(endDate));
            }
        } else {
            throw new Exception("查询区间类型不对，请检测查询参数格式");
        }
    }
    /**
     * 数字大小比较
     */
    private void wrapNumAreaQuery(Query query, String key, Object start, Object end, String ruleType) throws ParseException {
        if (">".equals(ruleType)) {
            query.addCriteria(Criteria.where(key).gt(start));
        } else if (">=".equals(ruleType)) {
            query.addCriteria(Criteria.where(key).gte(start));
        } else if ("<".equals(ruleType)) {
            query.addCriteria(Criteria.where(key).lt(end));
        } else if ("<=".equals(ruleType)) {
            query.addCriteria(Criteria.where(key).lte(end));
        } else if ("><=".equals(ruleType)) {
            query.addCriteria(Criteria.where(key).gt(start).lte(end));
        } else if (">=<".equals(ruleType)) {
            query.addCriteria(Criteria.where(key).gte(start).lt(end));
        } else if ("><".equals(ruleType)) {
            query.addCriteria(Criteria.where(key).gt(start).lt(end));
        } else {
            query.addCriteria(Criteria.where(key).gte(start).lte(end));
        }
    }
    /*in操作*/
    private void wrapInOperationQuery(Query query, String key, Object inList) {
        if (Objects.nonNull(inList)) {
            if (inList instanceof List) {
                List<Object> inList1 = (List) inList;
                query.addCriteria(Criteria.where(key).in(inList1));
            } else {
                query.addCriteria(Criteria.where(key).in(inList));
            }
        }
    }

    /**
     * 包装模糊查询query条件
     */
    private void wrapLikeQuery(Query query, String key, String part) {
//        String regex = "^.*" + part + ".*$";
//        Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
//        query.addCriteria(Criteria.where(key).regex(pattern));
        List<String> parts = Arrays.asList(part.split(","));
        List<Pattern> patterns = new ArrayList<>();
        parts.forEach(item -> {
            String regex = "^.*" + item + ".*$";
            Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
            patterns.add(pattern);
        });
        query.addCriteria(Criteria.where(key).in(patterns));
    }

    /**
     * 包装query条件
     */
    private void wrapNormalQuery(Query query, String key , Object condition) {
        query.addCriteria(Criteria.where(key).is(condition));
    }

    /**
     * 包装排序规则
     * @param
     * @return
     */
    private void wrapSortBy(Query query, Map<String, Object> sortBy) {
        List<Order> orderList = new ArrayList<>();
        sortBy.forEach((k, v) -> {
            Order orderK = (Integer) v == 1 ? Order.asc(k) : Order.desc(k);
            orderList.add(orderK);
        });
        query.with(Sort.by(orderList));
    }

    /**
     * 将需要返回的字段包装到Query对象
     * @param responseFields 返回的字段列表
     * @return
     */
    private void wrapQueryResponse(Query query, List<String> responseFields) {
        if (Objects.nonNull(responseFields)) {
            responseFields.forEach(query.fields()::include);
            query.fields().include("_id");
        }
    }


    /**
     * OR and查询
     */
    private void wrapOrOperationQuery(Query query, MongoRequestParamsHandler paramsHandler){
        List<List<Map<String, Object>>> orOperations = paramsHandler.getOrOperationList();
        try {
            if(!CollectionUtils.isEmpty(orOperations)){
                List criterias = new ArrayList();
//                Criteria[] criterias = new Criteria[];
                for(List<Map<String, Object>> orOperationList : orOperations){
                    String key = "";
                    List criteriaList = new ArrayList();
//                    Criteria[] criteriaList = new Criteria[orOperationList.size()];
                    for(int i = 0; i<orOperationList.size();i++){
                        Map<String, Object> queMap = orOperationList.get(i);
                        key = queMap.get("key").toString();
                        //先不支持int查询，业务原因 身份证可能全数字
//                        Object val = queMap.get("val");
//                        if(isInteger(val.toString())){
//                            val = Integer.valueOf(queMap.get("val").toString());
//                        }else{
//                            val = queMap.get("val").toString();
//                        }
                        Object val = queMap.get("val").toString();
                        String way = queMap.get("way").toString();
                        Criteria criteria;
                        switch (way){
                            case "eq":
                                criteria= Criteria.where(key).is(val);
                                break;
                            case "like":
                                String regex = "^.*" + val + ".*$";
                                Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
                                criteria= Criteria.where(key).regex(pattern);
                                break;
                            default:
                                criteria = new Criteria();
                                log.info(key+":字段不满足查询规范，现在支持eq LIKE 查询");
                        }
//                        criteriaList[i]=criteria;
                        criteriaList.add(criteria);
                    }
                    Criteria[] objects = (Criteria[]) criteriaList.toArray(new Criteria[criteriaList.size()]);
                    criterias.add(new Criteria().orOperator(objects));
                }
                Criteria[] objects = (Criteria[]) criterias.toArray(new Criteria[criterias.size()]);
                Criteria criteria = new Criteria().andOperator(objects);
                query.addCriteria(criteria);
            }
        }catch (Exception e){
            log.info(e.getMessage());
            log.info("拼装or查询条件失败，参数不满足要求");
        }
    }

    private void wrapNotNullOperationQuery(Query query, List<String> notNullList) {
        if (Objects.nonNull(notNullList)) {
            if (notNullList instanceof List) {
                for (String key : notNullList) {
                    query.addCriteria(Criteria.where(key).ne(null).andOperator(Criteria.where(key).exists(true)));
                }
            }
        }
    }
    private void wrapNullOperationQuery(Query query, List<String> nullList) {
        if (Objects.nonNull(nullList)) {
            if (nullList instanceof List) {
                for (String key : nullList) {
                    query.addCriteria(Criteria.where(key).in((Object) null));
                }
            }
        }
    }
}
